package com.itheima.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.itheima.exception.BusinessException;
import com.itheima.mapper.EmpExprMapper;
import com.itheima.mapper.EmpMapper;
import com.itheima.pojo.*;
import com.itheima.service.EmpLogService;
import com.itheima.service.EmpService;
import com.itheima.util.JwtUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 员工管理
 */
@Service
public class EmpServiceImpl implements EmpService {

    @Autowired
    private EmpMapper empMapper;
    @Resource
    private EmpExprMapper empExprMapper;
    @Resource
    private EmpLogService empLogService;


    /**
     * 要使用PageHelper简化分页查询的功能，只需要：
     * 1. 添加PageHelper的起步依赖
     * 2. 在Service层代码里：
     *  2.1 开启分页：PageHelper.startPage(页码, 每页几条)
     *  2.2 调用Mapper里查询列表的方法：查询列表的SQL语句中不需要再加 limit 起始索引,查询几行
     */
    @Override
    public PageBean<Emp> page(String name, Integer gender, LocalDate begin, LocalDate end, Integer page, Integer pageSize) {
        //开启分页
        PageHelper.startPage(page, pageSize);

        /*
        PageHelper的实际作用：会在Mybatis真正执行我们的SQL语句之前先拦截下来
            原本Mybatis执行的SQL是：select e.*, d.name deptName from .... where ....
            1. 改造SQL语句，改出来一条查询数量的SQL：select count(0) from .... where ....
                然后执行这条SQL，得到了符合查询条件的总数量
            2. 改造SQL语句，改出来一条分页查询列表的SQL：select e.*, d.name deptName from .... where .... limit 起始索引,查询几行
                其中起始索引和查询几行，因为我们提前执行PageHelper.startPage(页码,每页几行)
                PageHelper会根据这些参数进行计算，起始索引 = (页码-1)*每页几行
                之后执行这条SQL，得到了符合条件的、此页码的指定数量的 员工列表
            3. 将这2个结果存储到Page对象里返回给我们
         */
        //查询列表：PageHelper的分页，实际返回的是ArrayList的子类对象Page<Emp>
        List<Emp> empList = empMapper.pageList(name, gender, begin, end);

        //将List<Emp>强转成子类对象Page<Emp>。其中有total是总数量
        Page<Emp> p = (Page<Emp>) empList;

        //封装PageBean对象，其中要有total总数量，rows数据列表
        return new PageBean<>((int) p.getTotal(), empList);
    }

    /**
     * 事务管理注解@Transactional
     *  rollbackFor：用于设置什么异常时才会回滚事务。
     *      默认情况下，事务仅仅在方法里抛出了RuntimeException或Error时才会回滚。如果方法里抛出了编译时异常，是不会回滚的
     *      实际开发中，应该是只要有异常就回滚。我们可以修改这个参数
     *  propagation：用于设置事务的传播行为，指当出现事务的传播时，这个注解要如何处理事务
     *      事务的传播：
     *          一个业务(service)方法里 调用了 另一个业务(service)方法
     *          2个方法上都加了@Transactional注解， 事务从：调用者传播到了 被调用者
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(Emp emp) throws Exception {
        try {
            //1. 保存员工信息
            emp.setCreateTime(LocalDateTime.now());
            emp.setUpdateTime(LocalDateTime.now());
            emp.setPassword("123456");
            //  保存员工时，要获取到此员工的id
            empMapper.insert(emp);

            /*if (true) {
                throw new Exception("人造异常");
            }*/

            //2. 保存员工的工作经历列表
            List<EmpExpr> exprList = emp.getExprList();
            if (exprList != null && !exprList.isEmpty()) {
                //为集合里每个EmpExpr添加员工id
                for (EmpExpr empExpr : exprList) {
                    empExpr.setEmpId(emp.getId());
                }
                //再将集合批量保存到emp_expr表里
                empExprMapper.saveBatch(exprList);
            }
        } finally {
            EmpLog empLog = new EmpLog(null, LocalDateTime.now(), emp.toString());
            empLogService.insertLog(empLog);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteByIds(List<Integer> ids) {
        //如果集合ids为空：就什么都不用做
        if (ids == null || ids.isEmpty()) {
            return;
        }
        //调用EmpMapper删除员工
        empMapper.deleteByIds(ids);
        //调用EmpExprMapper删除员工的工作经历
        empExprMapper.deleteByEmpIds(ids);
    }

    @Override
    public Emp getById(Integer id) {
        Emp emp = empMapper.selectById(id);
        return emp;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateById(Emp emp) {
        //1. 修改员工信息
        emp.setUpdateTime(LocalDateTime.now());
        empMapper.updateById(emp);

        //2. 删除此员工的所有 旧的工作经历
        List<Integer> ids = new ArrayList<>();
        ids.add(emp.getId());
        empExprMapper.deleteByEmpIds(ids);

        //3。将参数里提交的工作经历列表，重新保存到emp_expr表里
        List<EmpExpr> exprList = emp.getExprList();
        if (exprList != null && !exprList.isEmpty()) {
            for (EmpExpr empExpr : exprList) {
                empExpr.setEmpId(emp.getId());
            }

            empExprMapper.saveBatch(exprList);
        }
    }

    @Override
    public List<Emp> queryAll() {
        return empMapper.selectAll();
    }

    @Override
    public LoginInfo login(Emp emp) {
        // 1、根据账号密码查询数据库。如果找不到，说明账号或者密码错误
        Emp e = empMapper.login(emp.getUsername(), emp.getPassword());
        if (e == null) {
             throw new BusinessException("账号或者密码错误");
        }

     // 2、登录成功了，要准备返回结果
        LoginInfo info = new LoginInfo();
        info.setId(e.getId());
        info.setUsername(e.getUsername());
        info.setName(e.getName());

        // 3、准备当前用户的令牌token
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", e.getId());
        claims.put("username", e.getUsername());
        // 将令牌存储到info对象中
        String token = JwtUtils.generateJwt(claims);
        info.setToken(token);

        return  info;
    }
}